#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
风险管理器
负责交易风险的监控和控制
"""

import asyncio
from typing import Dict, Any, Optional, List
from datetime import datetime, date
from decimal import Decimal

from config.config_manager import get_config
from utils.logger import get_logger, risk_log
from utils.exceptions import RiskError, StopLossTriggeredError, DailyLossLimitError
from core.base_classes import BaseRiskManager


class RiskManager(BaseRiskManager):
    """风险管理器"""

    def __init__(self, config: Optional[Dict[str, Any]] = None):
        if config is None:
            config = get_config()
            config = config.risk.__dict__ if hasattr(config, 'risk') else {}

        super().__init__(config)

        # 风险参数
        self.max_daily_loss = config.get('max_daily_loss', 5000)
        self.max_single_loss = config.get('max_single_loss', 1000)
        self.max_position_size = config.get('max_position_size', 10)
        self.stop_loss_points = config.get('stop_loss_points', 50)
        self.take_profit_points = config.get('take_profit_points', 150)
        self.enable_trailing_stop = config.get('enable_trailing_stop', False)
        self.trailing_stop_points = config.get('trailing_stop_points', 30)

        # 状态跟踪
        self.daily_pnl = 0.0
        self.daily_trades = []
        self.active_positions = {}
        self.trailing_stop_levels = {}

        self.logger.info("风险管理器初始化完成")

    async def check_position_risk(self, symbol: str, position: int,
                                entry_price: float, current_price: float) -> Dict[str, Any]:
        """检查持仓风险"""
        try:
            risk_info = {
                'symbol': symbol,
                'position': position,
                'entry_price': entry_price,
                'current_price': current_price,
                'stop_loss_triggered': False,
                'take_profit_triggered': False,
                'trailing_stop_triggered': False,
                'risk_level': 'low'
            }

            if position == 0:
                return risk_info

            # 计算浮动盈亏
            if position > 0:  # 多头
                pnl = (current_price - entry_price) * position * 10  # 假设每点10元
                risk_info['pnl'] = pnl

                # 止损检查
                if current_price <= entry_price - self.stop_loss_points:
                    risk_info['stop_loss_triggered'] = True
                    risk_info['risk_level'] = 'high'
                    risk_log(symbol, 'stop_loss', f'多头止损: {current_price} <= {entry_price - self.stop_loss_points}')

                # 止盈检查
                elif current_price >= entry_price + self.take_profit_points:
                    risk_info['take_profit_triggered'] = True
                    risk_info['risk_level'] = 'high'
                    risk_log(symbol, 'take_profit', f'多头止盈: {current_price} >= {entry_price + self.take_profit_points}')

                # 跟踪止损检查
                if self.enable_trailing_stop:
                    await self._check_trailing_stop(symbol, current_price, entry_price, 'long', risk_info)

            else:  # 空头
                pnl = (entry_price - current_price) * abs(position) * 10
                risk_info['pnl'] = pnl

                # 止损检查
                if current_price >= entry_price + self.stop_loss_points:
                    risk_info['stop_loss_triggered'] = True
                    risk_info['risk_level'] = 'high'
                    risk_log(symbol, 'stop_loss', f'空头止损: {current_price} >= {entry_price + self.stop_loss_points}')

                # 止盈检查
                elif current_price <= entry_price - self.take_profit_points:
                    risk_info['take_profit_triggered'] = True
                    risk_info['risk_level'] = 'high'
                    risk_log(symbol, 'take_profit', f'空头止盈: {current_price} <= {entry_price - self.take_profit_points}')

                # 跟踪止损检查
                if self.enable_trailing_stop:
                    await self._check_trailing_stop(symbol, current_price, entry_price, 'short', risk_info)

            return risk_info

        except Exception as e:
            self.logger.error(f"检查持仓风险失败 {symbol}: {e}")
            return {
                'symbol': symbol,
                'error': str(e),
                'risk_level': 'unknown'
            }

    async def _check_trailing_stop(self, symbol: str, current_price: float,
                                 entry_price: float, direction: str, risk_info: Dict[str, Any]):
        """检查跟踪止损"""
        try:
            if symbol not in self.trailing_stop_levels:
                # 初始化跟踪止损水平
                if direction == 'long':
                    self.trailing_stop_levels[symbol] = current_price - self.trailing_stop_points
                else:
                    self.trailing_stop_levels[symbol] = current_price + self.trailing_stop_points

            # 更新跟踪止损水平
            if direction == 'long':
                new_stop_level = current_price - self.trailing_stop_points
                if new_stop_level > self.trailing_stop_levels[symbol]:
                    self.trailing_stop_levels[symbol] = new_stop_level
                    self.logger.debug(f"更新多头跟踪止损: {symbol} -> {new_stop_level}")

                # 检查是否触发跟踪止损
                if current_price <= self.trailing_stop_levels[symbol]:
                    risk_info['trailing_stop_triggered'] = True
                    risk_info['risk_level'] = 'high'
                    risk_log(symbol, 'trailing_stop', f'多头跟踪止损: {current_price} <= {self.trailing_stop_levels[symbol]}')

            else:  # short
                new_stop_level = current_price + self.trailing_stop_points
                if new_stop_level < self.trailing_stop_levels[symbol]:
                    self.trailing_stop_levels[symbol] = new_stop_level
                    self.logger.debug(f"更新空头跟踪止损: {symbol} -> {new_stop_level}")

                # 检查是否触发跟踪止损
                if current_price >= self.trailing_stop_levels[symbol]:
                    risk_info['trailing_stop_triggered'] = True
                    risk_info['risk_level'] = 'high'
                    risk_log(symbol, 'trailing_stop', f'空头跟踪止损: {current_price} >= {self.trailing_stop_levels[symbol]}')

        except Exception as e:
            self.logger.error(f"跟踪止损检查失败 {symbol}: {e}")

    async def check_daily_risk(self, current_pnl: float) -> bool:
        """检查日风险"""
        try:
            await self.reset_daily_stats()

            if current_pnl <= -self.max_daily_loss:
                risk_log('SYSTEM', 'daily_loss_limit', f'日亏损限制触发: {current_pnl} <= -{self.max_daily_loss}')
                return True

            return False

        except Exception as e:
            self.logger.error(f"检查日风险失败: {e}")
            return False

    def calculate_stop_loss_price(self, entry_price: float, direction: str) -> float:
        """计算止损价格"""
        if direction == 'BUY':
            return entry_price - self.stop_loss_points
        else:
            return entry_price + self.stop_loss_points

    def calculate_take_profit_price(self, entry_price: float, direction: str) -> float:
        """计算止盈价格"""
        if direction == 'BUY':
            return entry_price + self.take_profit_points
        else:
            return entry_price - self.take_profit_points

    async def validate_order(self, symbol: str, direction: str, volume: int,
                           price: Optional[float] = None) -> Dict[str, Any]:
        """验证订单风险"""
        try:
            validation_result = {
                'valid': True,
                'warnings': [],
                'errors': []
            }

            # 检查持仓限制
            current_position = self.active_positions.get(symbol, 0)
            new_position = current_position + volume if direction == 'BUY' else current_position - volume

            if abs(new_position) > self.max_position_size:
                validation_result['valid'] = False
                validation_result['errors'].append(
                    f"持仓超过限制: {abs(new_position)} > {self.max_position_size}"
                )

            # 检查单次亏损风险
            if price and self.active_positions.get(symbol):
                entry_price = self.active_positions[symbol].get('entry_price')
                if entry_price:
                    potential_loss = abs(price - entry_price) * volume * 10  # 假设每点10元
                    if potential_loss > self.max_single_loss:
                        validation_result['warnings'].append(
                            f"潜在亏损较大: {potential_loss} > {self.max_single_loss}"
                        )

            return validation_result

        except Exception as e:
            self.logger.error(f"验证订单失败: {e}")
            return {
                'valid': False,
                'errors': [f"验证失败: {e}"]
            }

    async def record_trade(self, trade_info: Dict[str, Any]):
        """记录交易"""
        try:
            self.daily_trades.append({
                'timestamp': datetime.now(),
                'symbol': trade_info.get('symbol'),
                'direction': trade_info.get('direction'),
                'volume': trade_info.get('volume'),
                'price': trade_info.get('price'),
                'pnl': trade_info.get('pnl', 0)
            })

            # 更新持仓信息
            symbol = trade_info.get('symbol')
            direction = trade_info.get('direction')
            volume = trade_info.get('volume')
            price = trade_info.get('price')

            if symbol:
                if symbol not in self.active_positions:
                    self.active_positions[symbol] = {
                        'position': 0,
                        'entry_price': 0,
                        'total_cost': 0
                    }

                current_pos = self.active_positions[symbol]
                if direction == 'BUY':
                    new_position = current_pos['position'] + volume
                    new_cost = current_pos['total_cost'] + (price * volume)
                    current_pos['position'] = new_position
                    if new_position > 0:
                        current_pos['entry_price'] = new_cost / (price * new_position)
                        current_pos['total_cost'] = new_cost
                else:
                    new_position = current_pos['position'] - volume
                    current_pos['position'] = new_position
                    if new_position < 0:
                        current_pos['entry_price'] = price
                        current_pos['total_cost'] = price * abs(new_position)

                # 清理空持仓
                if current_pos['position'] == 0:
                    del self.active_positions[symbol]

        except Exception as e:
            self.logger.error(f"记录交易失败: {e}")

    async def get_portfolio_risk(self) -> Dict[str, Any]:
        """获取投资组合风险"""
        try:
            total_exposure = 0
            total_pnl = 0
            risk_positions = []

            for symbol, position_info in self.active_positions.items():
                position = position_info['position']
                entry_price = position_info['entry_price']

                exposure = abs(position) * entry_price * 10  # 假设每点10元
                total_exposure += exposure

                # 估算当前盈亏（需要实时价格，这里简化处理）
                # 在实际实现中需要从数据管理器获取实时价格
                estimated_pnl = 0  # 这里应该计算实际盈亏
                total_pnl += estimated_pnl

                risk_positions.append({
                    'symbol': symbol,
                    'position': position,
                    'entry_price': entry_price,
                    'exposure': exposure,
                    'estimated_pnl': estimated_pnl
                })

            return {
                'total_exposure': total_exposure,
                'total_pnl': total_pnl,
                'positions_count': len(risk_positions),
                'positions': risk_positions,
                'risk_level': self._calculate_portfolio_risk_level(total_exposure, total_pnl)
            }

        except Exception as e:
            self.logger.error(f"获取投资组合风险失败: {e}")
            return {'error': str(e)}

    def _calculate_portfolio_risk_level(self, exposure: float, pnl: float) -> str:
        """计算投资组合风险等级"""
        try:
            # 简单的风险等级计算逻辑
            if pnl < -exposure * 0.1:  # 亏损超过10%
                return 'high'
            elif pnl < -exposure * 0.05:  # 亏损超过5%
                return 'medium'
            else:
                return 'low'
        except:
            return 'unknown'

    async def emergency_stop(self, reason: str):
        """紧急停止"""
        self.logger.critical(f"触发紧急停止: {reason}")

        # 清理所有持仓跟踪
        self.active_positions.clear()
        self.trailing_stop_levels.clear()

        risk_log('SYSTEM', 'emergency_stop', f'紧急停止已触发: {reason}')

    def get_risk_summary(self) -> Dict[str, Any]:
        """获取风险摘要"""
        try:
            return {
                'daily_pnl': self.daily_pnl,
                'daily_trades_count': len(self.daily_trades),
                'active_positions_count': len(self.active_positions),
                'max_daily_loss': self.max_daily_loss,
                'max_single_loss': self.max_single_loss,
                'max_position_size': self.max_position_size,
                'trailing_stop_enabled': self.enable_trailing_stop,
                'last_reset_date': self.last_reset_date.isoformat() if self.last_reset_date else None
            }
        except Exception as e:
            self.logger.error(f"获取风险摘要失败: {e}")
            return {'error': str(e)}


# 全局风险管理器实例
_risk_manager = None

def get_risk_manager() -> RiskManager:
    """获取全局风险管理器实例"""
    global _risk_manager
    if _risk_manager is None:
        _risk_manager = RiskManager()
    return _risk_manager

def init_risk_manager(config: Optional[Dict[str, Any]] = None) -> RiskManager:
    """初始化风险管理器"""
    global _risk_manager
    _risk_manager = RiskManager(config)
    return _risk_manager
